/**************************************************************************
*   Copyright (C) 2009 Chernov Dmitry                                     *
*   diman4ik.chernov@gmail.com                                            *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#include "korners_scene.h"
#include "korners_render.h"
#include "korners_graphics_items.h"
#include "korners_engine_thread.h"

#include <QGraphicsPixmapItem>
#include <KMessageBox>
#include <KLocale>
#include <KGamePopupItem>
#include <QPainter>
#include <KDebug>
#include <QGraphicsSceneMouseEvent>
#include <QVector>


KornersScene::KornersScene( QObject *parent ) : QGraphicsScene(parent), 
                                                m_playFieldBorderSize(0), 
                                                m_cellSize(32)
{
    KornersRender::self()->setCellSize( m_cellSize );
    
    m_popupItem = new KGamePopupItem;
    addItem(m_popupItem);

    // Create all game caps
    KornersCapItem* cap;
    for(int i = 0; i < KornersEngine::N_CAPS; i++)
    {
        if( i < KornersEngine::N_CAPS/2 )
            cap = new KornersCapItem(   KornersRender::self()->opponentCapPixmap(),
                                        KornersCapItem::opponent );
        else
            cap = new KornersCapItem(   KornersRender::self()->playerCapPixmap(),
                                        KornersCapItem::player );
        cap->setZValue(3);
        cap->setVisible(true);
        addItem(cap);
    }

    m_curMovingCap = 0;
    m_canPlay = true;
    m_gameOver = false;
    m_timeGame = false;
    m_gameStarted = false;

    connect( &m_moveTimeLine, SIGNAL( newFrame(int) ), SLOT( moveAnimationFrameChanged(int) ) );
    connect( &m_moveTimeLine, SIGNAL( finished() ), SLOT( moveAnimFinished() ) );

    KornersEngineThread* thread = new KornersEngineThread(this);

    connect( this, SIGNAL( startGameEngineAI() ), thread, SLOT( startGameEngineAI() ) );
    connect( this, SIGNAL( startGameEngineDual() ), thread, SLOT( startGameEngineDual() ) );
    connect( this, SIGNAL( startGameEngineTimer() ), thread, SLOT( startGameEngineTimer() ) );
    
    connect( this, SIGNAL( startGameEngineNetwork( const QString& , int , bool , const QString& ) ),  
             thread, SLOT( startGameEngineNetwork( const QString& , int , bool , const QString& ) ) );

    resetScene();
}

KornersScene::~KornersScene()
{}

void KornersScene::resizeScene( int width, int height )
{
    bool hasBorder = KornersRender::self()->hasBorderElement();

    int minDim = qMin( width, height );
    // border width is hardcoded to be half of cell size.
    // take it into account if it exists
    m_cellSize = hasBorder ?    minDim/(KornersEngine::FIELD_SIZE+1) : 
                                minDim/KornersEngine::FIELD_SIZE;

    // set it only if current theme supports it
    m_playFieldBorderSize = hasBorder ? m_cellSize/2 : 0;

    int boardSize = m_cellSize * KornersEngine::FIELD_SIZE;
    kDebug() << "board size : " << boardSize;

    m_playFieldRect.setX( width/2 - boardSize/2 - m_playFieldBorderSize );
    m_playFieldRect.setY( height/2 - boardSize/2 - m_playFieldBorderSize );

    m_playFieldRect.setWidth( boardSize + m_playFieldBorderSize*2 );
    m_playFieldRect.setHeight( boardSize + m_playFieldBorderSize*2 );

    setSceneRect( 0, 0, width, height );

    // sets render sizes for cells
    kDebug() << "setting cell size" << m_cellSize;
    KornersRender::self()->setCellSize( m_cellSize );

    KornersCapItem* cap;

    foreach( QGraphicsItem* item, items() )
    {
        cap = qgraphicsitem_cast<KornersCapItem*>(item);
        if(cap)
        {
            if( cap->whos() == KornersCapItem::opponent )
                cap->setPixmap( KornersRender::self()->opponentCapPixmap() );
            else
                cap->setPixmap( KornersRender::self()->playerCapPixmap() );
            

            cap->setOffset(fieldToPix(cap->getPos().x(), cap->getPos().y()));
        }
    }
}

void KornersScene::putCapsInStartPos()
{
    int players  = 0;
    int opponents = 0;
    KornersCapItem* cap;

    foreach( QGraphicsItem* item, items() )
    {
        cap = qgraphicsitem_cast<KornersCapItem*>(item);
        if(cap)
        {
            if( cap->whos() == KornersCapItem::opponent )
            {
		
                cap->setPos( QPoint( opponents%4, opponents/4 ) );
                opponents++;
            }
            else
            {
                cap->setPos( QPoint( players%4 + 4, players/4 + 5 ) );
                players++;
            }
            cap->setOffset( fieldToPix( cap->getPos().x(), cap->getPos().y() ) );
        }
    }
}

void KornersScene::startNetworkGameClient(const QString& net_name, int port, const QString& ip_adress)
{
    m_canPlay = false;
    m_name = net_name;
    m_gameStarted = true;

    emit( startGameEngineNetwork( net_name, port, false, ip_adress ) );

    resetScene();
    
    emit( started() );
}

void KornersScene::startNetworkGameServer(const QString& net_name, int port)
{
    m_canPlay = false;
    m_name = net_name;
    m_gameOver = false;
    m_gameStarted = true;
 
    emit( startGameEngineNetwork( net_name, port, true ) );

    resetScene();
    
    emit( started() );
}

void KornersScene::startNewLocalGame( bool multiplayer )
{
    if( m_gameStarted )
    {
        m_gameStarted = false;
        m_canPlay = true;
        resetScene();
        return;
    }
    
    if( multiplayer )
	emit( startGameEngineDual() );
    else
    {
	if( m_timeGame )
  	    emit( startGameEngineTimer() );
 	else
	    emit( startGameEngineAI() );
    }

    m_gameOver = false;
    m_gameStarted = true;
    
    emit( started() );
    emit( newStatus2( i18n("Your turn") ) );
}

void KornersScene::resetScene()
{
    kDebug() << "reset scene";

    m_capSelected = false;
    m_popupItem->forceHide();

    unshowPaths();
    
    putCapsInStartPos();
}

void KornersScene::mousePressEvent( QGraphicsSceneMouseEvent* evt)
{
    if( !m_canPlay )
    {
        kDebug() << "can't play";
        return;
    }

    if( m_moveTimeLine.running() )
        return;

    QGraphicsScene::mousePressEvent(evt);
    QRect boardRect = m_playFieldRect.adjusted( m_playFieldBorderSize,
                                                m_playFieldBorderSize,
                                                -m_playFieldBorderSize,
                                                -m_playFieldBorderSize );
    
    if ( !boardRect.contains( evt->scenePos().toPoint() ) )
    {
        m_capSelected = false;
        unshowPaths();
        return;
    }
    if(evt->button() == Qt::LeftButton)
    {
        QPoint pnt = pixToField( evt->scenePos() );
        if(m_capSelected)
        {
            unshowPaths();

            point_destination = pnt;
            m_capSelected = false;
            m_canPlay = false;

            emit( playerMadeMove( point_source, point_destination ) );
            emit( newStatus2( i18n("Wait ... ") ) );
        }
        else
        {
            QGraphicsItem* item = itemAt(evt->scenePos());
            KornersCapItem* cap = qgraphicsitem_cast<KornersCapItem*>(item);
            if(cap)
            {   
                if( !m_gameStarted )
                    startNewLocalGame(false);

                point_source = pnt;
		emit( capSelected(point_source) );
            }
        }
    }
}

void KornersScene::showPaths( const QVector<QPoint>* moves )
{
    m_capSelected = true;
    int startX = m_playFieldRect.x() + m_playFieldBorderSize;
    int startY = m_playFieldRect.y() + m_playFieldBorderSize;
    for(int i = 0; i < moves->size(); i++)
    {
        KornersHighlightItem* hl = new KornersHighlightItem();
        hl->setPixmap( KornersRender::self()->moveHighlightPixmap() );
        hl->setOffset( startX + moves->at(i).x()*m_cellSize, startY + moves->at(i).y()*m_cellSize );
        hl->setZValue(2);
        hl->setVisible(true);
        addItem(hl);
    }
}

void KornersScene::unshowPaths()
{
    QList<QGraphicsItem*> itemlist = items();
    KornersHighlightItem* hl;

    foreach( QGraphicsItem* item, itemlist )
    {
        hl = qgraphicsitem_cast<KornersHighlightItem*>(item);
        if( hl)
        {
            removeItem(item);
        }
    }       emit( newStatus2( i18n("Your turn") ) );
}

void KornersScene::drawBackground( QPainter* p, const QRectF& )
{
    QPixmap tile = KornersRender::self()->backgroundTilePixmap();
    
    p->drawPixmap( 0, 0, KornersRender::self()->backgroundPixmap(sceneRect().size().toSize()) );

    p->drawPixmap( m_playFieldRect.x(), m_playFieldRect.y(),
                   KornersRender::self()->backgroundBorderPixmap( m_playFieldRect.size() ) );

    int startX = m_playFieldRect.x() + m_playFieldBorderSize;
    int maxX = m_playFieldRect.x() + m_cellSize*KornersEngine::FIELD_SIZE;
    int startY = m_playFieldRect.y() + m_playFieldBorderSize;
    int maxY = m_playFieldRect.y() + m_cellSize*KornersEngine::FIELD_SIZE;

    for(int x=startX; x<maxX; x+=m_cellSize)
        for(int y=startY; y<maxY; y+=m_cellSize)
            p->drawPixmap( x, y, tile );
}

void KornersScene::moveAnimationFrameChanged(int frame)
{
    if( !m_curMovingCap )
    {
        KornersMove curMove = m_pendingMoves.first();
        QPointF coords = fieldToPix(curMove.points[0].x(), curMove.points[0].y());
        coords += QPoint(m_cellSize/2, m_cellSize/2);
        QGraphicsItem* item = itemAt(coords);
        if(item)
        {

            KornersCapItem* cap = qgraphicsitem_cast<KornersCapItem*>(item);
            if(cap)
            {
                m_curMovingCap = cap;
            
                if(curMove.points.size() > 2)
                {
                    m_curMovingCap->setOffset(fieldToPix(curMove.points[2].x(), curMove.points[2].y()));      // Ход с прыжком(ами)
                }
                else
                {
                    m_curMovingCap->setOffset(fieldToPix(curMove.points[1].x(), curMove.points[1].y()));      // Ход на одну клетку
                }
            }
        }
    }
    else
    {
        KornersMove curMove = m_pendingMoves.first();
        if( (frame + 1)*2 < curMove.points.size() )
        {
            m_curMovingCap->setOffset(  fieldToPix(curMove.points[(frame + 1)*2].x(),
                                        curMove.points[(frame + 1)*2].y()));       
        }
    }
}

void KornersScene::showMovePath( KornersMove mv )
{
    m_pendingMoves.push_back(mv);
      
    if( !m_moveTimeLine.running() )
    {
        startMoveAnimation( m_pendingMoves.first() );
    }
}

void KornersScene::moveAnimFinished()
{
    KornersCapItem::owner lastAnim = KornersCapItem::player;
    if( m_curMovingCap != 0 )
    {
        m_curMovingCap->setPos( m_pendingMoves.first().points.last() );
	lastAnim = m_curMovingCap->whos();
        m_curMovingCap = 0;
    }

    m_pendingMoves.pop_front();

    // getting the next move
    if( !m_pendingMoves.isEmpty() )
    {
        startMoveAnimation( m_pendingMoves.first() );
    }
    else
    {
	if( m_timeGame )
	{
	    if( lastAnim == KornersCapItem::opponent )
		emit( startTiming() );
	}
    }
}

bool KornersScene::startMoveAnimation(const KornersMove& mv)
{
    // Route points are separated by 1 cell always (if not short move)
    int frames = mv.points.size()/2;
    if( frames > 0 )
    {
        m_moveTimeLine.startFrames(frames);        
        return true;
    }
    return false;
}

void KornersScene::showEngineMess( QString txt )
{
    m_popupItem->setMessageTimeout( 1500 );
    m_popupItem->showMessage( txt, KGamePopupItem::BottomLeft, KGamePopupItem::ReplacePrevious );
}

void KornersScene::opponentName( QString name )
{
    emit( newStatus1( m_name + " vs " + name ) );
}

void KornersScene::canPlay()
{
    if( !m_gameOver )
    {
        m_canPlay = true;
        emit( newStatus2( i18n("Your turn") ) );
    }
}

void KornersScene::toggleOnTime( bool onTime )
{
    m_timeGame = onTime;
}

void KornersScene::youWin()
{
    m_gameOver = true;
    m_popupItem->setMessageTimeout( 2500 );
    m_popupItem->showMessage(   i18n("Congratulations you are the winner!!!"), 
                                KGamePopupItem::BottomLeft, KGamePopupItem::ReplacePrevious );
    emit( newStatus2( i18n("Game over") ) );
    emit( gameOver( m_time ) );
}

void KornersScene::youLost()
{
    m_gameOver = true;
    m_popupItem->setMessageTimeout( 2500 );
    m_popupItem->showMessage(   i18n("Sorry, you've lost!!!"), 
                                KGamePopupItem::BottomLeft, KGamePopupItem::ReplacePrevious );
    emit( newStatus2( i18n("Game over") ) );
    emit( gameOver( QTime(0, 0, 0) ) );
}

void KornersScene::newTime( QTime time )
{
    if( ( !m_gameOver ) && ( m_gameStarted ) )
    {
        m_time = time;
        emit( newStatus1( time.toString( "hh:mm:ss.zzz" ) ) );
    }
}
